package 位运算;

/*亦或运算 记住： 就是 无进位相加  忽略 进位
 * 1.亦或运算 满足交换律  和交换律 简单来说 就是 同样一批数 无论 怎样的顺序亦或 ^ 运算 最终的结果都是一样的 
 *   x ^ x=0； 这是一个重要的性质 x^ 0=x;  a*2+1==a>>1|1  乘二加一的操作
 * 以上 就是一些 重要的性质
 * 2。题型 : 有一个数组中 有一个数 出现 了奇数次  其他的 数 都出现 偶数次 怎样找到 并打印这个数
 * 把数组中所有的 数 都亦或起来 最后的结果  就是那个数   用的性质是1
 * ***  提取最右侧的 1
 * 用到一些 前提知识   找到  一个数n 以二进制数的形式呈现中的 最右边的 那个1   RightOne
 *   n&(~n+1)  这就可以直接找到 RightOne  巧妙  你学算法的目的 就是 为了 面试 不用想太多其他的东西  能写对 就行 
 * 
 * 3. 给出一个数组 有两个数 出现了  奇数次 其他的 数 出现了  偶数次  求出 这两个数   并打印   这两个数
 * 记住这道题的 解题思路  和方法 
 * 
 * 
 * 
 * 拓展 提取一 （1） 的题型：
 * 数一个数 中 一（1）的 个数
 * 
 */
public class 位运算 {
	public static void main(String []args) {
		System.out.println("hello world!");
		int num=5;
		System.out.println(num^num^num);
		// 与一1 取亦或 运算并不是  取非 操作的  还是要实际操作的  看看为好
		System.out.println(num^1);
		//  测试 没问题的  就这样 很稳 牛逼 特拉斯
		System.out.println(oneCounts(15));
		int arr[]= {3,3,4,6,7,4,5,5,5,5,4,6};
		findAB(arr);
	}
	public static int oneCounts(int n) {
		int counts=0;
		while(n!=0) {
			int rightOne = n&(~n+1);
			// 下面这一步 是直接 将 n  中最右侧的 1 给抹掉 进行下一次 的  统计 
			n^=rightOne;
			counts++;
		}
		return counts;
	}
//  给定一个数组 ： 数组中 出现 a，b 奇数次 其他 全是 偶数次 求 a，b
	public static void  findAB(int []arr) {
		int zero=0;
		for(int i=0;i<arr.length;i++) {
			zero^=arr[i];
		}
		int zeroPlus=0;
		//此时的结果 就是  zero  =a^b;  下面分别求出 a和 b
		int rightOne=zero&(~zero+1);
		for(int i=0;i<arr.length;i++) {
			// 这里的 判断 是   &完之后  !=0;  也挺合理的 的说实话  
			if((rightOne & arr[i])==rightOne) {
				    zeroPlus^=arr[i];
			}
		}
		int a=zeroPlus;
		int b=a^zero;
		System.out.println("a的值是"+a+"b的值是"+b);
	}



	/*
	  给你一个字符串
	  判断改字符串 中的字符 ，每个是不是只出现一次

	// 尽量不要使用额外的数据结构！
	这其实 也间接 提示了
	使用 bit 位 来存储信息
	 */
	public boolean isUnique(String astr) {
		int len = astr.length();
		if(len >26)
			return false;
		int bit = 0;
		/*
		 这里 还有另外 一种  位 运算的方式
		 那就是 1 << ch - 'a'
		 对 该位 上的值 进行 判断 是否 为 1
		 我感觉不如 现在这种的实现方式, 最后统一进行 1 的判断
		 */
		for(char ch : astr.toCharArray()){
			bit ^=  1 << ch - 'a';
		}
		Integer.bitCount(bit);
		return oneCounts(bit) == len;
	}






}
